#include "sc_car_def_loader.h"
#include "sc_car_def_manager.h"

bool ScCarDefLoader::load( ScCarDefManager& carDefManager, const BeFile* befile ) const
{
	TiXmlDocument document;
	const bool result = document.LoadFile( befile->getFullFilename().c_str() );
	if(result)
	{
		const TiXmlElement* const rootElementPtr=document.RootElement();
		if(rootElementPtr)
		{
			const TiXmlElement& rootElement=(*rootElementPtr);
			const TiXmlElement* elementPtr=rootElement.FirstChildElement();
			while(elementPtr)
			{
				const TiXmlElement& element=(*elementPtr);
				if(element.ValueTStr()=="wheel")
				{
					std::string id;
					float radius = 0;
					float width = 0;
					float friction = 1;
					std::string objPath;
					BeXmlHelper<5> xmlHelper;
					xmlHelper.addString("id", id);
					xmlHelper.addFloat("radius", radius);
					xmlHelper.addFloat("width", width);
					xmlHelper.addFloat("friction", friction);
					xmlHelper.addString("obj_path", objPath);
					xmlHelper.parse(element);
					
					std::string fullObjPath( befile->getDirectory() );
					fullObjPath.append(objPath);
					carDefManager.createWheel(id, radius, width, friction, fullObjPath);
				}
				else if(element.ValueTStr()=="suspension")
				{
					std::string id;
					float stiffness;
					float damping;
					float compression;
					float length;
					float rollInfluence;
					float maximumForce;
					BeXmlHelper<7> xmlHelper;
					xmlHelper.addString("id", id);
					xmlHelper.addFloat("stiffness", stiffness);
					xmlHelper.addFloat("damping", damping);
					xmlHelper.addFloat("compression", compression);
					xmlHelper.addFloat("length", length);
					xmlHelper.addFloat("roll_influence", rollInfluence);
					xmlHelper.addFloat("maximum_force", maximumForce);
					xmlHelper.parse(element);
					carDefManager.createSuspension(id, stiffness, damping, compression, length, rollInfluence, maximumForce);
				}
				else if(element.ValueTStr()=="engine")
				{
					std::string id;
					float force = 0;
					BeXmlHelper<2> xmlHelper;
					xmlHelper.addString("id", id);
					xmlHelper.addFloat("force", force);
					xmlHelper.parse(element);
					carDefManager.createEngine(id, force);
				}
				else if(element.ValueTStr()=="brakes")
				{
					std::string id;
					float force = 0;
					BeXmlHelper<2> xmlHelper;
					xmlHelper.addString("id", id);
					xmlHelper.addFloat("force", force);
					xmlHelper.parse(element);
					carDefManager.createBrakes(id, force);
				}
				else if(element.ValueTStr()=="chassis")
				{
					loadChassis(carDefManager, element, befile->getDirectory() );
				}
				else if(element.ValueTStr()=="car")
				{
					loadCar(carDefManager, element);
				}
				elementPtr=element.NextSiblingElement();
			}
		}
		return true;
	}
	return false;
}

void ScCarDefLoader::loadChassis( ScCarDefManager& carDefManager, const TiXmlElement& element, const std::string& path ) const
{
	std::string id;
	std::string dimensions;
	float mass = 0;
	std::string objPath;
	BeXmlHelper<4> helper;
	helper.addString("id", id);
	helper.addString("dimensions", dimensions);
	helper.addFloat("mass", mass);
	helper.addString("obj_path", objPath);
	helper.parse(element);

	float x=0;
	float y=0;
	float z=0;
	sscanf(dimensions.c_str(), "%f, %f, %f", &x, &y, &z);

	Vector3f halfDimensions(x, y, z);

	//Parse Wheel attachments here
	ScChassisDef::WheelPairAttachments wheelPairAttachments;

	const TiXmlElement* childElementPtr = element.FirstChildElement();
	while(childElementPtr)
	{
		const TiXmlElement& childElement=*childElementPtr;
		if(childElement.ValueTStr()=="wheel_pair_attachment")
		{
			float offset = 0;
			float engineBias = 0;
			float brakeBias = 0;
			float steeringInfluence = 0;
			float axleLength = 0;
			std::string leftWheelId;
			std::string leftSuspensionId;
			std::string rightWheelId;
			std::string rightSuspensionId;
			BeXmlHelper<9> xmlHelper;
			xmlHelper.addFloat("offset", offset);
			xmlHelper.addFloat("axle_length", axleLength);
			xmlHelper.addFloat("engine_bias", engineBias);
			xmlHelper.addFloat("brake_bias", brakeBias);
			xmlHelper.addFloat("steering_influence", steeringInfluence);
			xmlHelper.addString("left_wheel", leftWheelId);
			xmlHelper.addString("left_suspension", leftSuspensionId);
			xmlHelper.addString("right_wheel", rightWheelId);
			xmlHelper.addString("right_suspension", rightSuspensionId);
			xmlHelper.parse(childElement);

			const ScWheelDef* const leftWheel=carDefManager.getWheel(leftWheelId);
			const ScSuspensionDef* const leftSuspension=carDefManager.getSuspension(leftSuspensionId);
			const ScWheelDef* const rightWheel=carDefManager.getWheel(rightWheelId);
			const ScSuspensionDef* const rightSuspension=carDefManager.getSuspension(rightSuspensionId);
			
			wheelPairAttachments.push_back( new ScWheelPairAttachment(offset, axleLength, engineBias, brakeBias, steeringInfluence, leftWheel, leftSuspension, rightWheel, rightSuspension) );
		}
		childElementPtr=childElement.NextSiblingElement();
	}

	halfDimensions.x/=2;
	halfDimensions.y/=2;
	halfDimensions.z/=2;

	std::string fullObjPath( path );
	fullObjPath.append(objPath);
	carDefManager.createChassis(id, halfDimensions, mass, wheelPairAttachments, fullObjPath);
}

void ScCarDefLoader::loadCar( ScCarDefManager& carDefManager, const TiXmlElement& element ) const
{
	std::string id;
	std::string chassisId;
	std::string engineId;
	std::string brakesId;
	BeXmlHelper<4> helper;
	helper.addString("id", id);
	helper.addString("chassis", chassisId);
	helper.addString("engine", engineId);
	helper.addString("brakes", brakesId);
	helper.parse(element);
	const ScChassisDef* const chassisDef=carDefManager.getChassis(chassisId);
	assert(chassisDef);
	const ScEngineDef* const engineDef=carDefManager.getEngine(engineId);
	assert(engineDef);
	const ScBrakesDef* const brakesDef=carDefManager.getBrakes(brakesId);
	assert(brakesDef);
	carDefManager.createCar(id, *chassisDef, *engineDef, *brakesDef);
}
